/*
 * Copyright 2007-2009 Taglab Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.taglab.chic.taglib;

import org.springframework.web.util.HtmlUtils;

import java.io.FilterWriter;
import java.io.Writer;
import java.io.IOException;

/**
 * Simple Writer that escapes reserved XML entities.
 *
 * @author Markus Kobler
 */
class EscapingXmlWriter extends FilterWriter {

  /**
   * Temporary buffer used to hold writes of strings and single characters
   */
  private char[] writeBuffer;

  /**
   * Size of writeBuffer, must be >= 1
   */
  private final int writeBufferSize = 1024;
  

  public EscapingXmlWriter(Writer out) {
    super(out);
  }

  @Override  
  public void write(int c) throws IOException {
    switch( c ) {
      case '&':
        out.write("&amp;");
        break;
      case '<':
        out.write("&lt;");
        break;
      case '>':
        out.write("&gt;");
        break;
      default:
        out.write(c);
    }    
  }

  @Override
  public void write(char[] cbuf, int off, int len) throws IOException {
    if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) ) {
      throw new IndexOutOfBoundsException();
    } else if (len == 0) {
      return;
    }
    int start=off;
    for( int i=off; i<(off + len); i++) {
      switch( cbuf[i] ) {
        case '&':
          out.write(cbuf, start, i-start);
          out.write("&amp;");
          start = i+1;
          continue;
        case '<':
          out.write(cbuf, start, i-start);
          out.write("&lt;");
          start = i+1;
          continue;
        case '>':
          out.write(cbuf, start, i-start);
          out.write("&gt;");
          start = i+1;
          continue;
      }
    }
    // Output any remaining text
    if( len-(start-off) > 0 ) {
      out.write(cbuf, start, len-(start-off));
    }
  }

  @Override
  public void write(String str, int off, int len) throws IOException {
    char cbuf[];
    if (len <= writeBufferSize) {
      if (writeBuffer == null) {
        writeBuffer = new char[writeBufferSize];
      }
      cbuf = writeBuffer;
    } else {	// Don't permanently allocate very large buffers.
      cbuf = new char[len];
    }    
    str.getChars(off, (off + len), cbuf, 0);
    write(cbuf, 0, len);
  }
  
}
